﻿using System;
using System.Collections.Generic;
using System.Text;

namespace TerminationCall.Core {
    public class TileField : ICloneable {

        private Dictionary<TileFields, Tile> _tiles;
        private Dictionary<int, TileFields> _tileOrders;

        public TileField() {
            _tiles = new Dictionary<TileFields, Tile>();
            _tileOrders = new Dictionary<int, TileFields>();

            _tiles.Add(TileFields.TopTile, null);
            _tiles.Add(TileFields.MiddleTile, null);
            _tiles.Add(TileFields.BottomTile, null);
            _tiles.Add(TileFields.LeftTopTile, null);
            _tiles.Add(TileFields.LeftMiddleTile, null);
            _tiles.Add(TileFields.LeftBottomTile, null);
            _tiles.Add(TileFields.RightTopTile, null);
            _tiles.Add(TileFields.RightMiddleTile, null);
            _tiles.Add(TileFields.RightBottomTile, null);

            _tileOrders.Add(0, TileFields.MiddleTile);
            _tileOrders.Add(1, TileFields.TopTile);
            _tileOrders.Add(2, TileFields.BottomTile);
            _tileOrders.Add(3, TileFields.LeftMiddleTile);
            _tileOrders.Add(4, TileFields.RightMiddleTile);
            _tileOrders.Add(5, TileFields.LeftTopTile);
            _tileOrders.Add(6, TileFields.RightTopTile);
            _tileOrders.Add(7, TileFields.LeftBottomTile);
            _tileOrders.Add(8, TileFields.RightBottomTile);
        }

        /// <summary>
        /// Gets all setted tiles of the current Field object.
        /// </summary>
        public Tile[] Tiles {
            get {
                List<Tile> tiles = new List<Tile>();

                for (int i = 8; i >= 0; i--) {
                    SetTileToListIfSetted(_tiles[_tileOrders[i]], tiles);
                }

                return tiles.ToArray();
            }
        }

        public Tile GetTile(TileFields fieldTile) {
            return _tiles[fieldTile];
        }

        public void SetTile(TileFields fieldTile, Tile tile) {

            if (fieldTile == TileFields.MiddleTile) {
                SetTile(tile);
                return;
            }
            
            _tiles[fieldTile] = tile;
            SetTileFieldToTop(fieldTile);
        }

        public void SetTileFast(TileFields fieldTile, Tile tile) {
            _tiles[fieldTile] = tile;
        }

        public void SetTile(Tile tile) {

            _tiles[TileFields.TopTile] = null;
            _tiles[TileFields.BottomTile] = null;
            _tiles[TileFields.LeftMiddleTile] = null;
            _tiles[TileFields.LeftTopTile] = null;
            _tiles[TileFields.LeftBottomTile] = null;
            _tiles[TileFields.RightTopTile] = null;
            _tiles[TileFields.RightMiddleTile] = null;
            _tiles[TileFields.RightBottomTile] = null;

            _tiles[TileFields.MiddleTile] = tile;

            SetTileFieldToTop(TileFields.MiddleTile);

        }

        public object Clone() {

            TileField field = new TileField();

            field._tiles[TileFields.BottomTile] = _tiles[TileFields.BottomTile];
            field._tiles[TileFields.LeftBottomTile] = _tiles[TileFields.LeftBottomTile];
            field._tiles[TileFields.LeftMiddleTile] = _tiles[TileFields.LeftMiddleTile];
            field._tiles[TileFields.LeftTopTile] = _tiles[TileFields.LeftTopTile];
            field._tiles[TileFields.MiddleTile] = _tiles[TileFields.MiddleTile];
            field._tiles[TileFields.RightBottomTile] = _tiles[TileFields.RightBottomTile];
            field._tiles[TileFields.RightMiddleTile] = _tiles[TileFields.RightMiddleTile];
            field._tiles[TileFields.RightTopTile] = _tiles[TileFields.RightTopTile];
            field._tiles[TileFields.TopTile] = _tiles[TileFields.TopTile];
            
            field._tileOrders[0] = _tileOrders[0];
            field._tileOrders[1] = _tileOrders[1];
            field._tileOrders[2] = _tileOrders[2];
            field._tileOrders[3] = _tileOrders[3];
            field._tileOrders[4] = _tileOrders[4];
            field._tileOrders[5] = _tileOrders[5];
            field._tileOrders[6] = _tileOrders[6];
            field._tileOrders[7] = _tileOrders[7];
            field._tileOrders[8] = _tileOrders[8];
            
            return field;
        }

        private void SetTileToListIfSetted(Tile tile, List<Tile> tiles) {
            if (tile != null) {
                tiles.Add(tile);
            }
        }

        private void SetTileFieldToTop(TileFields tileField) {

            if (tileField == TileFields.MiddleTile) {

                _tileOrders[0] = TileFields.MiddleTile;
                _tileOrders[1] = TileFields.TopTile;
                _tileOrders[2] = TileFields.BottomTile;
                _tileOrders[3] = TileFields.LeftMiddleTile;
                _tileOrders[4] = TileFields.RightMiddleTile;
                _tileOrders[5] = TileFields.LeftTopTile;
                _tileOrders[6] = TileFields.RightTopTile;
                _tileOrders[7] = TileFields.LeftBottomTile;
                _tileOrders[8] = TileFields.RightBottomTile;

                return;

            }

            int currentKey = GetCurrentKeyOfTileField(tileField);

            for (int i = currentKey; i > 0; i--) {
                _tileOrders[i] = _tileOrders[i - 1];
            }

            _tileOrders[0] = tileField;

        }

        private int GetCurrentKeyOfTileField(TileFields tileField) {

            foreach (int key in _tileOrders.Keys) {

                if (_tileOrders[key] == tileField) {
                    return key;
                }

            }

            return 8;

        }

    }
}
